package com.project.frba.bifront.server.rpc;

import java.awt.Color;
import java.awt.Font;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.MultiplePiePlot;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.util.TableOrder;
import org.springframework.context.ApplicationContext;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.project.frba.bi.BiUtil;
import com.project.frba.bi.descriptor.Descriptor;
import com.project.frba.bi.descriptor.DescriptorsLoader;
import com.project.frba.bi.queueing.OlapDAO;
import com.project.frba.bifront.client.model.BarChartInformation;
import com.project.frba.bifront.client.model.ChartInformation;
import com.project.frba.bifront.client.model.Cube;
import com.project.frba.bifront.client.model.CubeDataRow;
import com.project.frba.bifront.client.model.Dashboard;
import com.project.frba.bifront.client.model.LineChartInformation;
import com.project.frba.bifront.client.model.PieChartInformation;
import com.project.frba.bifront.client.rpc.ChartServices;

public class ChartServicesImpl extends RemoteServiceServlet implements ChartServices{
	
	private static int DEFAULT_HEIGHT = 380;
	private static int DEFAULT_WIDTH = 600;
	
	public String doPieChart(PieChartInformation info, Integer width, Integer height){
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		
		Cube cube = getData(info);
		
		for (CubeDataRow dataRow : cube.getRows()) {
			dataset.setValue(new Integer(dataRow.getData()), dataRow.getValue(info.getRowPropertyName()), dataRow.getValue(info.getColumnPropertyName()));
		}
		
		TableOrder tableOrder = info.getColLayout() ? TableOrder.BY_COLUMN : TableOrder.BY_ROW;
		JFreeChart chart = 	ChartFactory.createMultiplePieChart(
													info.getTitle(), 
													dataset, 
													tableOrder, 
													info.getIncludeLegend(), 
													true, 
													false);
		
		MultiplePiePlot plot = (MultiplePiePlot) chart.getPlot();
		JFreeChart subchart = plot.getPieChart();
	    PiePlot p = (PiePlot) subchart.getPlot();
	    p.setBackgroundPaint(null);
	    p.setOutlineStroke(null);
	    p.setLabelGenerator(new StandardPieSectionLabelGenerator(
	                "{2}", NumberFormat.getNumberInstance(), NumberFormat.getPercentInstance()
	            ));
	   	p.setLabelFont(new Font("SansSerif", Font.PLAIN, 9));
        p.setInteriorGap(0.08);
		
        return saveToDisk(info, chart, width, height);
		
	}
	
	public String doPieChart(PieChartInformation info) {
		return doPieChart(info, DEFAULT_WIDTH, DEFAULT_HEIGHT);		
	}

	
	
	public String doLineChart(LineChartInformation info, Integer width, Integer height) {
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		Cube cube = getData(info);
		
		for (CubeDataRow dataRow : cube.getRows()) {
			dataset.addValue(new Integer(dataRow.getData()), dataRow.getValue(info.getRowPropertyName()), dataRow.getValue(info.getColumnPropertyName()));
		}
		
		 final JFreeChart chart = ChartFactory.createLineChart(
		            info.getTitle(),       // chart title
		            info.getDomainAxisLabel(),                    // domain axis label
		            info.getRangeAxisLabel(),                   // range axis label
		            dataset,                   // data
		            PlotOrientation.VERTICAL,  // orientation
		            info.getIncludeLegend(),   // include legend
		            true,                      // tooltips
		            false                      // urls
		        );
		 
        chart.setBackgroundPaint(Color.white);
        CategoryPlot plot = (CategoryPlot) chart.getPlot();
        plot.setBackgroundPaint(Color.lightGray);
        plot.setRangeGridlinePaint(Color.white);

        NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
        rangeAxis.setAutoRangeIncludesZero(true);
		
		return saveToDisk(info, chart, width, height);
	}
	
	public String doLineChart(LineChartInformation info) {
		return doLineChart(info, DEFAULT_WIDTH, DEFAULT_HEIGHT);
	}

	public String doBarChart(BarChartInformation info, Integer width, Integer height) {
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		Cube cube = getData(info);
		
		for (CubeDataRow dataRow : cube.getRows()) {
			dataset.addValue(new Integer(dataRow.getData()), dataRow.getValue(info.getRowPropertyName()), dataRow.getValue(info.getColumnPropertyName()));
		}
		
		JFreeChart chart = ChartFactory.createBarChart(
				info.getTitle(), // chart title
				info.getDomainAxisLabel(), // domain axis label
				info.getRangeAxisLabel(), // range axis label
				dataset, // data
				PlotOrientation.VERTICAL, // orientation
				info.getIncludeLegend(), // include legend
				true, // tooltips?
				false // URLs?
				);
		
		chart.setBackgroundPaint(Color.white);
        CategoryPlot plot = (CategoryPlot) chart.getPlot();
        plot.setBackgroundPaint(Color.lightGray);
        plot.setRangeGridlinePaint(Color.white);

        NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
        rangeAxis.setAutoRangeIncludesZero(true);
		
		return saveToDisk(info, chart, width, height);
	}
	
	public String doBarChart(BarChartInformation info) {
		return doBarChart(info, DEFAULT_WIDTH, DEFAULT_HEIGHT);
	}
	
	public String doChart(String serializedChart, Integer width, Integer height){
		Map<String, String> chartInformationMap = BiUtil.deserializeChart(serializedChart);
		String chartClass = chartInformationMap.get("class");
		
		if("PieChartInformation".equals(chartClass)){
			PieChartInformation chartInfo = new PieChartInformation();
			chartInfo.build(chartInformationMap);
			return doPieChart(chartInfo, width, height);
		} else if("LineChartInformation".equals(chartClass)) {
			LineChartInformation chartInfo = new LineChartInformation();
			chartInfo.build(chartInformationMap);
			return doLineChart(chartInfo, width, height);
		} else if("BarChartInformation".equals(chartClass)) {
			BarChartInformation chartInfo = new BarChartInformation();
			chartInfo.build(chartInformationMap);
			return doBarChart(chartInfo, width, height);
		}
			
		return null;
	}
	
	public Map<Integer, String> doChart(Dashboard dashboard){
		Map<Integer, String> chartUrls = new HashMap<Integer, String>();

		
		if(Dashboard.DUAL.equals(dashboard.getType())){
			if (dashboard.getFirst() != null){
				chartUrls.put(1, doChart(dashboard.getFirst(), Dashboard.WIDTH, Dashboard.DUAL_HEIGHT));				
			}
			if (dashboard.getSecond() != null) {
				chartUrls.put(2, doChart(dashboard.getSecond(), Dashboard.WIDTH, Dashboard.DUAL_HEIGHT));				
			}
		} else if (Dashboard.QUAD.equals(dashboard.getType())) {
			if (dashboard.getFirst() != null){
				chartUrls.put(1, doChart(dashboard.getFirst(), Dashboard.WIDTH, Dashboard.QUAD_HEIGHT));
			}
			if (dashboard.getSecond() != null){
				chartUrls.put(2, doChart(dashboard.getSecond(), Dashboard.WIDTH, Dashboard.QUAD_HEIGHT));
			}
			if (dashboard.getThird() != null){
				chartUrls.put(3, doChart(dashboard.getThird(), Dashboard.WIDTH, Dashboard.QUAD_HEIGHT));
			}
			if (dashboard.getFourth() != null){
				chartUrls.put(4, doChart(dashboard.getFourth(), Dashboard.WIDTH, Dashboard.QUAD_HEIGHT));
			}
		}
		
		return chartUrls;
	}
	
	public Cube getData(ChartInformation info){
		String rowProperty = info.getRowPropertyName();
		String colProperty = info.getColumnPropertyName();
		
		ApplicationContext context = BiUtil.getApplicationContext();
		OlapDAO dao = (OlapDAO)context.getBean("olapDao");
		
		Descriptor descriptor = DescriptorsLoader.getDescriptorByName(info.getDescriptorName());
		List<String> properties = new ArrayList<String>();
		properties.add(rowProperty);
		properties.add(colProperty);
		
		
		return dao.getData(info.getSql(), properties, descriptor);
	}
	
	private String saveToDisk(ChartInformation info, JFreeChart chart, Integer width, Integer height) {
		try {
			GregorianCalendar calendar = new GregorianCalendar();
			String fileName = info.getDescriptorName() + 
				calendar.get(GregorianCalendar.YEAR) + 
				calendar.get(GregorianCalendar.MONTH + 1) + 
				calendar.get(GregorianCalendar.DAY_OF_MONTH) +
				calendar.getTimeInMillis() + ".png";
			String filePath = BiUtil.getRepositoryPath() + fileName; 
			OutputStream outStream = new FileOutputStream(filePath);
			ChartUtilities.writeChartAsPNG(outStream, chart, width, height);
			outStream.close();
			return fileName;
		} catch (Exception e) {
			//Loguear la excepcion
			return null;
		}
	}

	
}
